src/libostree/ostree-bootloader-uboot.c \
src/libostree/ostree-ordered-hash.h \
src/libostree/ostree-ordered-hash.c \
+ src/libostree/ostree-gpg-verifier.c \
+ src/libostree/ostree-gpg-verifier.h \
$(NULL)
if USE_LIBARCHIVE
libostree_1_la_SOURCES += src/libostree/ostree-libarchive-input-stream.h \
if USE_GPGME
libostree_1_la_LIBADD += $(GPGME_LIBS)
+
+gpgreadme_DATA = src/libostree/README-gpg
+gpgreadmedir = $(pkgdatadir)
endif
testfiles = test-basic \
test-archivez \
test-remote-add \
+ test-commit-sign \
test-corruption \
test-libarchive \
test-pull-archive-z \
-Subproject commit e0b2fefbb69d03f7aa1390f723e4dfc46f301e71
+Subproject commit 020fa7de344d9f10136ae1a3cb9bf6baa868218d
--- /dev/null
+Any GPG keyring files ending in ".gpg" placed in this directory will
+be automatically trusted by OSTree.
--- /dev/null
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters@verbum.org>
+ * Copyright (C) 2013 Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+ */
+
+#include "ostree-gpg-verifier.h"
+#include "otutil.h"
+
+#define GPGVGOODPREFIX "[GNUPG:] GOODSIG "
+
+typedef struct {
+ GObjectClass parent_class;
+} OstreeGpgVerifierClass;
+
+struct OstreeGpgVerifier {
+ GObject parent;
+
+ GList *keyrings;
+ gchar *homedir;
+};
+
+static void _ostree_gpg_verifier_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (OstreeGpgVerifier, _ostree_gpg_verifier, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, _ostree_gpg_verifier_initable_iface_init))
+
+static void
+ostree_gpg_verifier_finalize (GObject *object)
+{
+ OstreeGpgVerifier *self = OSTREE_GPG_VERIFIER (object);
+
+ g_list_free_full (self->keyrings, g_object_unref);
+ g_free (self->homedir);
+
+ G_OBJECT_CLASS (_ostree_gpg_verifier_parent_class)->finalize (object);
+}
+
+static void
+_ostree_gpg_verifier_class_init (OstreeGpgVerifierClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ostree_gpg_verifier_finalize;
+}
+
+static void
+_ostree_gpg_verifier_init (OstreeGpgVerifier *self)
+{
+}
+
+static gboolean
+ostree_gpg_verifier_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ OstreeGpgVerifier *self = (OstreeGpgVerifier*)initable;
+ const char *default_keyring_path = g_getenv ("OSTREE_GPG_HOME");
+ gs_unref_object GFile *default_keyring_dir = NULL;
+ gs_unref_object GFile *default_pubring_file = NULL;
+ gs_unref_object GFile *default_pubring = NULL;
+
+ if (!default_keyring_path)
+ default_keyring_path = DATADIR "/ostree/trusted.gpg.d/";
+
+ default_keyring_dir = g_file_new_for_path (default_keyring_path);
+ default_pubring_file = g_file_get_child (default_keyring_dir, "pubring.gpg");
+
+ if (!_ostree_gpg_verifier_add_keyring (self, default_pubring_file,
+ cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static void
+_ostree_gpg_verifier_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = ostree_gpg_verifier_initable_init;
+}
+
+typedef struct {
+ OstreeGpgVerifier *self;
+ GCancellable *cancellable;
+ gboolean gpgv_done;
+ gboolean status_done;
+
+ gint goodsigs;
+ gint exitcode;
+ GError *error;
+ GMainLoop *loop;
+} VerifyRun;
+
+static void
+_gpgv_parse_line (VerifyRun *v, const gchar *line)
+{
+ if (g_str_has_prefix (line, GPGVGOODPREFIX))
+ v->goodsigs++;
+}
+
+static void
+on_process_done (GObject *s, GAsyncResult *res, gpointer user_data)
+{
+ VerifyRun *v = user_data;
+ gs_subprocess_wait_finish (GS_SUBPROCESS (s), res,
+ &v->exitcode, &v->error);
+
+ v->gpgv_done = TRUE;
+
+ g_main_loop_quit (v->loop);
+}
+
+static void
+on_read_line (GObject *s, GAsyncResult *res, gpointer user_data)
+{
+ VerifyRun *v = user_data;
+ gchar *line;
+
+ /* Ignore errors when reading from the data input */
+ line = g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (s),
+ res, NULL, NULL);
+
+ if (line == NULL)
+ {
+ v->status_done = TRUE;
+ g_main_loop_quit (v->loop);
+ }
+ else
+ {
+ _gpgv_parse_line (v, line);
+ g_free (line);
+ g_data_input_stream_read_line_async (G_DATA_INPUT_STREAM (s),
+ G_PRIORITY_DEFAULT, v->cancellable,
+ on_read_line, v);
+ }
+}
+
+
+gboolean
+_ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
+ GFile *file,
+ GFile *signature,
+ gboolean *out_had_valid_sig,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gboolean ret_had_valid_sig = FALSE;
+ gs_unref_object GSSubprocessContext *context = NULL;
+ gs_unref_object GSSubprocess *proc = NULL;
+ gs_unref_object GDataInputStream *data = NULL;
+ gs_free gchar *status_fd_str = NULL;
+ GInputStream *output;
+ gint fd;
+ VerifyRun v = { 0, };
+ GList *item;
+ GMainContext *maincontext = NULL;
+ GMainLoop *loop = NULL;
+
+ g_return_val_if_fail (out_had_valid_sig != NULL, FALSE);
+
+ maincontext = g_main_context_new ();
+ loop = g_main_loop_new (maincontext, FALSE);
+
+ g_main_context_push_thread_default (maincontext);
+
+ context = gs_subprocess_context_newv ("gpgv", NULL);
+ gs_subprocess_context_set_stdin_disposition (context,
+ GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
+ gs_subprocess_context_set_stdout_disposition (context,
+ GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
+ gs_subprocess_context_set_stderr_disposition (context,
+ GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
+
+ if (!gs_subprocess_context_open_pipe_read (context, &output, &fd, error))
+ goto out;
+
+ status_fd_str = g_strdup_printf ("%d", fd);
+ gs_subprocess_context_argv_append (context, "--status-fd");
+ gs_subprocess_context_argv_append (context, status_fd_str);
+
+ for (item = self->keyrings ; item != NULL; item = g_list_next (item))
+ {
+ GFile *keyring = item->data;
+ gs_subprocess_context_argv_append (context, "--keyring");
+ gs_subprocess_context_argv_append (context, gs_file_get_path_cached (keyring));
+ }
+
+ gs_subprocess_context_argv_append (context, gs_file_get_path_cached (signature));
+ gs_subprocess_context_argv_append (context, gs_file_get_path_cached (file));
+
+ proc = gs_subprocess_new (context, cancellable, error);
+ if (proc == NULL)
+ goto out;
+
+ data = g_data_input_stream_new (output);
+
+ v.self = self;
+ v.cancellable = cancellable;
+ v.loop = loop;
+
+ gs_subprocess_wait (proc, cancellable, on_process_done, &v);
+ g_data_input_stream_read_line_async (data, G_PRIORITY_DEFAULT, cancellable,
+ on_read_line, &v);
+
+ while (!v.gpgv_done || !v.status_done)
+ g_main_loop_run (loop);
+
+ if (v.goodsigs > 0)
+ ret_had_valid_sig = TRUE;
+
+ ret = TRUE;
+ *out_had_valid_sig = ret_had_valid_sig;
+ out:
+ if (maincontext)
+ {
+ g_main_context_pop_thread_default (maincontext);
+ g_main_context_unref (maincontext);
+ }
+ if (loop)
+ g_main_loop_unref (loop);
+
+ return ret;
+}
+
+void
+_ostree_gpg_verifier_set_homedir (OstreeGpgVerifier *self,
+ const gchar *path)
+{
+ g_free (self->homedir);
+ self->homedir = g_strdup (path);
+}
+
+gboolean
+_ostree_gpg_verifier_add_keyring (OstreeGpgVerifier *self,
+ GFile *path,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ self->keyrings = g_list_append (self->keyrings, g_object_ref (path));
+ return TRUE;
+}
+
+gboolean
+_ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self,
+ GFile *path,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_object GFileEnumerator *enumerator = NULL;
+
+ enumerator = g_file_enumerate_children (path, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NONE,
+ cancellable, error);
+ if (!enumerator)
+ goto out;
+
+ while (TRUE)
+ {
+ GFileInfo *file_info;
+ GFile *path;
+
+ if (!gs_file_enumerator_iterate (enumerator, &file_info, &path,
+ cancellable, error))
+ goto out;
+ if (file_info == NULL)
+ break;
+
+ if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR &&
+ g_str_has_suffix (g_file_info_get_name (file_info), ".gpg"))
+ self->keyrings = g_list_append (self->keyrings, g_object_ref (path));
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+OstreeGpgVerifier*
+_ostree_gpg_verifier_new (GCancellable *cancellable,
+ GError **error)
+{
+ return g_initable_new (OSTREE_TYPE_GPG_VERIFIER, cancellable, error, NULL);
+}
--- /dev/null
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters@verbum.org>
+ * Copyright (C) 2013 Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+ */
+
+//#pragma once
+
+#include "config.h"
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define OSTREE_TYPE_GPG_VERIFIER _ostree_gpg_verifier_get_type()
+#define OSTREE_GPG_VERIFIER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_GPG_VERIFIER, OstreeGpgVerifier))
+#define OSTREE_IS_GPG_VERIFIER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_GPG_VERIFIER))
+
+typedef struct OstreeGpgVerifier OstreeGpgVerifier;
+
+GType _ostree_gpg_verifier_get_type (void);
+
+OstreeGpgVerifier *_ostree_gpg_verifier_new (GCancellable *cancellable,
+ GError **error);
+
+gboolean _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
+ GFile *file,
+ GFile *signature,
+ gboolean *had_valid_signature,
+ GCancellable *cancellable,
+ GError **error);
+
+void _ostree_gpg_verifier_set_homedir (OstreeGpgVerifier *self,
+ const gchar *path);
+
+gboolean _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self,
+ GFile *path,
+ GCancellable *cancellable,
+ GError **error);
+
+gboolean _ostree_gpg_verifier_add_keyring (OstreeGpgVerifier *self,
+ GFile *path,
+ GCancellable *cancellable,
+ GError **error);
+G_END_DECLS
gboolean transaction_resuming;
volatile gint n_scanned_metadata;
SoupURI *fetching_sync_uri;
+
+ gboolean gpg_verify;
GThread *metadata_thread;
GMainContext *metadata_thread_context;
goto out;
}
+#ifdef HAVE_GPGME
+ if (pull_data->gpg_verify)
+ {
+ if (!ostree_repo_verify_commit (pull_data->repo,
+ checksum,
+ NULL,
+ NULL,
+ cancellable,
+ error))
+ goto out;
+ }
+#endif
+
if (!ostree_repo_load_variant (pull_data->repo, OSTREE_OBJECT_TYPE_COMMIT, checksum,
&commit, error))
goto out;
goto out;
pull_data->base_uri = soup_uri_new (baseurl);
+#ifdef HAVE_GPGME
+ if (!ot_keyfile_get_boolean_with_default (config, remote_key, "gpg-verify",
+ TRUE, &pull_data->gpg_verify, error))
+ goto out;
+#else
+ pull_data->gpg_verify = FALSE;
+#endif
+
if (!ot_keyfile_get_boolean_with_default (config, remote_key, "tls-permissive",
FALSE, &tls_permissive, error))
goto out;
#include "ostree-core-private.h"
#include "ostree-repo-private.h"
#include "ostree-repo-file.h"
+#include "ostree-repo-file-enumerator.h"
+#include "ostree-gpg-verifier.h"
#ifdef HAVE_GPGME
#include <locale.h>
config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
g_string_append_printf (config_data, "mode=%s\n", mode_str);
+
if (!g_file_replace_contents (self->config_file,
config_data->str,
config_data->len,
return ret;
}
+/**
+ * ostree_repo_verify_commit:
+ * @self: Repository
+ * @commit_checksum: ASCII SHA256 checksum
+ * @keyringdir: (allow-none): Path to directory GPG keyrings; overrides built-in default if given
+ * @extra_keyring: (allow-none): Path to additional keyring file (not a directory)
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Check for a valid GPG signature on commit named by the ASCII
+ * checksum @commit_checksum.
+ */
+gboolean
+ostree_repo_verify_commit (OstreeRepo *self,
+ const gchar *commit_checksum,
+ GFile *keyringdir,
+ GFile *extra_keyring,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_object OstreeGpgVerifier *verifier = NULL;
+ gs_unref_variant GVariant *commit_variant = NULL;
+ gs_unref_object GFile *commit_tmp_path = NULL;
+ gs_unref_object GFile *keyringdir_ref = NULL;
+ gs_unref_variant GVariant *metadata = NULL;
+ gs_unref_variant GVariant *signaturedata = NULL;
+ gs_free gchar *commit_filename = NULL;
+ gint i, n;
+ gboolean had_valid_signataure = FALSE;
+
+ if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT,
+ commit_checksum, &commit_variant,
+ error))
+ goto out;
+
+ verifier = _ostree_gpg_verifier_new (cancellable, error);
+ if (!verifier)
+ goto out;
+
+ if (keyringdir)
+ {
+ if (!_ostree_gpg_verifier_add_keyring_dir (verifier, keyringdir,
+ cancellable, error))
+ goto out;
+ }
+ if (extra_keyring != NULL)
+ {
+ if (!_ostree_gpg_verifier_add_keyring (verifier, extra_keyring,
+ cancellable, error))
+ goto out;
+ }
+
+ if (!ostree_repo_read_commit_detached_metadata (self,
+ commit_checksum,
+ &metadata,
+ cancellable,
+ error))
+ {
+ g_prefix_error (error, "Failed to read detached metadata: ");
+ goto out;
+ }
+
+ if (metadata)
+ signaturedata = g_variant_lookup_value (metadata, "ostree.gpgsigs", G_VARIANT_TYPE ("aay"));
+ if (!signaturedata)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ "No signatures found");
+ goto out;
+ }
+
+ if (!gs_file_open_in_tmpdir (self->tmp_dir, 0644,
+ &commit_tmp_path, NULL,
+ cancellable, error))
+ goto out;
+
+ if (!g_file_replace_contents (commit_tmp_path,
+ (char*)g_variant_get_data (commit_variant),
+ g_variant_get_size (commit_variant),
+ NULL, FALSE, 0, NULL,
+ cancellable, error))
+ goto out;
+
+ n = g_variant_n_children (signaturedata);
+ for (i = 0; i < n; i++)
+ {
+ GVariant *signature_variant = g_variant_get_child_value (signaturedata, i);
+ gs_unref_object GFile *temp_sig_path = NULL;
+
+ if (!gs_file_open_in_tmpdir (self->tmp_dir, 0644,
+ &temp_sig_path, NULL,
+ cancellable, error))
+ goto out;
+
+ if (!g_file_replace_contents (temp_sig_path,
+ (char*)g_variant_get_data (signature_variant),
+ g_variant_get_size (signature_variant),
+ NULL, FALSE, 0, NULL,
+ cancellable, error))
+ goto out;
+
+ if (!_ostree_gpg_verifier_check_signature (verifier,
+ commit_tmp_path,
+ temp_sig_path,
+ &had_valid_signataure,
+ cancellable, error))
+ {
+ (void) gs_file_unlink (temp_sig_path, NULL, NULL);
+ goto out;
+ }
+ (void) gs_file_unlink (temp_sig_path, NULL, NULL);
+ if (had_valid_signataure)
+ break;
+ }
+
+ if (!had_valid_signataure)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "GPG signatures found, but none are in trusted keyring");
+ goto out;
+ }
+
+ ret = TRUE;
+out:
+ if (commit_tmp_path)
+ (void) gs_file_unlink (commit_tmp_path, NULL, NULL);
+ return ret;
+}
+
#endif
const gchar *homedir,
GCancellable *cancellable,
GError **error);
+
+gboolean ostree_repo_verify_commit (OstreeRepo *self,
+ const gchar *commit_checksum,
+ GFile *keyringdir,
+ GFile *extra_keyring,
+ GCancellable *cancellable,
+ GError **error);
#endif
G_END_DECLS
if (!g_file_query_exists (dir, NULL))
{
gs_unref_object OstreeRepo *repo = ostree_repo_new (repo_dir);
- if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE, cancellable, error))
+ if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE,
+ cancellable, error))
goto out;
}
if (origin_remote)
{
+ OstreeRepoPullFlags pullflags = 0;
char *refs_to_fetch[] = { origin_ref, NULL };
g_print ("Fetching remote %s ref %s\n", origin_remote, origin_ref);
- if (!ostree_repo_pull (repo, origin_remote, refs_to_fetch, OSTREE_REPO_PULL_FLAGS_NONE,
+ if (!ostree_repo_pull (repo, origin_remote, refs_to_fetch, pullflags,
cancellable, error))
goto out;
}
export TEST_GPG_KEYID="472CDAFA"
export TEST_GPG_HOME=${SRCDIR}/gpghome
+export OSTREE_GPG_HOME=${TEST_GPG_HOME}
if test -n "${OT_TESTS_DEBUG}"; then
set -x
cd ${test_tmpdir}
mkdir repo
${CMD_PREFIX} ostree --repo=repo init
-${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo
${CMD_PREFIX} ostree --repo=repo pull origin main
${CMD_PREFIX} ostree --repo=repo fsck
echo "ok pull"
echo "ok upgrade bare"
os_repository_new_commit
-ostree --repo=sysroot/ostree/repo remote add testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime
+ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime
ostree admin --sysroot=sysroot upgrade --os=testos
origrev=${rev}
rev=${newrev}
# Commit + upgrade twice, so that we'll rotate out the original deployment
bootcsum1=${bootcsum}
os_repository_new_commit
-ostree --repo=sysroot/ostree/repo remote add testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime
+ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime
ostree admin --sysroot=sysroot upgrade --os=testos
bootcsum2=${bootcsum}
os_repository_new_commit "1"
bootcsum3=${bootcsum}
-ostree --repo=sysroot/ostree/repo remote add testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime
+ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime
ostree admin --sysroot=sysroot upgrade --os=testos
rev=${newrev}
cd ${test_tmpdir}
mkdir repo2
${CMD_PREFIX} ostree --repo=repo2 init
-${CMD_PREFIX} ostree --repo=repo2 remote add aremote file://$(pwd)/repo test2
+${CMD_PREFIX} ostree --repo=repo2 remote add --set=gpg-verify=false aremote file://$(pwd)/repo test2
ostree --repo=repo2 pull aremote
ostree --repo=repo2 rev-parse aremote/test2
ostree --repo=repo2 fsck
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) 2013 Jeremy Whiting <jeremy.whiting@collabora.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+set -e
+
+if ! ostree --version | grep -q -e '\+gpgme'; then
+ exit 77
+fi
+
+. $(dirname $0)/libtest.sh
+
+keyid="472CDAFA"
+oldpwd=`pwd`
+mkdir ostree-srv
+cd ostree-srv
+mkdir gnomerepo
+${CMD_PREFIX} ostree --repo=gnomerepo init --mode="archive-z2"
+mkdir gnomerepo-files
+cd gnomerepo-files
+echo first > firstfile
+mkdir baz
+echo moo > baz/cow
+echo alien > baz/saucer
+${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "A remote commit" -m "Some Commit body" --gpg-sign=$keyid --gpg-homedir=${SRCDIR}/gpghome
+mkdir baz/deeper
+${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "Add deeper" --gpg-sign=$keyid --gpg-homedir=${SRCDIR}/gpghome
+echo hi > baz/deeper/ohyeah
+mkdir baz/another/
+echo x > baz/another/y
+${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "The rest" --gpg-sign=$keyid --gpg-homedir=${SRCDIR}/gpghome
+cd ..
+rm -rf gnomerepo-files
+
+cd ${test_tmpdir}
+mkdir ${test_tmpdir}/httpd
+cd httpd
+ln -s ${test_tmpdir}/ostree-srv ostree
+ostree trivial-httpd --daemonize -p ${test_tmpdir}/httpd-port
+port=$(cat ${test_tmpdir}/httpd-port)
+echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address
+cd ${oldpwd}
+
+export OSTREE="ostree --repo=repo"
+
+repopath=${test_tmpdir}/ostree-srv/gnomerepo
+cp -a ${repopath} ${repopath}.orig
+
+# Set OSTREE_GPG_HOME to a place with no keyrings, we shouldn't trust the signature
+cd ${test_tmpdir}
+mkdir repo
+${CMD_PREFIX} ostree --repo=repo init
+${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+if env OSTREE_GPG_HOME=${test_tmpdir} ${CMD_PREFIX} ostree --repo=repo pull origin main; then
+ assert_not_reached "pull with no trusted GPG keys unexpectedly succeeded!"
+fi
+rm repo -rf
+
+# And a test case with valid signature
+cd ${test_tmpdir}
+mkdir repo
+${CMD_PREFIX} ostree --repo=repo init
+${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+${CMD_PREFIX} ostree --repo=repo pull origin main
+rm repo -rf
+
+# A test with corrupted detached signature
+cd ${test_tmpdir}
+find ${test_tmpdir}/ostree-srv/gnomerepo -name '*.commitmeta' | while read fname; do
+ echo borkborkbork > ${fname};
+done
+mkdir repo
+${CMD_PREFIX} ostree --repo=repo init
+${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+if ${CMD_PREFIX} ostree --repo=repo pull origin main; then
+ assert_not_reached "pull with corrupted signature unexpectedly succeeded!"
+fi
+rm repo -rf
+
+# And now attempt to pull the same corrupted commit, but with GPG
+# verification off
+cd ${test_tmpdir}
+mkdir repo
+${CMD_PREFIX} ostree --repo=repo init
+${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo
+${CMD_PREFIX} ostree --repo=repo pull origin main
+rm repo -rf
rm repo -rf
mkdir repo
${CMD_PREFIX} ostree --repo=repo init
- ${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+ ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo
if ${CMD_PREFIX} ostree --repo=repo pull origin main; then
assert_not_reached "pull unexpectedly succeeded!"
fi
rm repo -rf
mkdir repo
${CMD_PREFIX} ostree --repo=repo init
-${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo
maxtries=`find ${repopath}/objects | wc -l`
maxtries=`expr $maxtries \* 2`